package cn.itrigger.dynamic.sql.select;

import cn.itrigger.dynamic.sql.select.render.SelectStatementProvider;
import cn.itrigger.dynamic.sql.structure.BasicColumn;
import cn.itrigger.dynamic.sql.select.QueryExpressionDSL.FromGatherer;
import cn.itrigger.dynamic.sql.select.QueryExpressionDSL.FromGathererBuilder;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * @author admin
 * @date 2018/9/26
 **/
public class SelectDSL<R> {
    private Function<SelectModel, R> adapterFunction;
    private List<QueryExpressionModel> queryExpressions = new ArrayList<>();
    private OrderByModel orderByModel;

    private SelectDSL(Function<SelectModel, R> adapterFunction) {
        this.adapterFunction = adapterFunction;
    }

    private FromGatherer<R> queryExpressionBuilder(BasicColumn ... selectList) {
        return new FromGathererBuilder<R>()
                .withSelectDSL(this)
                .withSelectList(selectList)
                .build();
    }

    private FromGatherer<R> distinctQueryExpressionBuilder(BasicColumn ... selectList) {
        return new FromGathererBuilder<R>()
                .withSelectDSL(this)
                .withSelectList(selectList)
                .isDistinct()
                .build();
    }

    public static FromGatherer<SelectModel> select(BasicColumn ... selectList) {
        return select(Function.identity(), selectList);
    }

    public static <R> FromGatherer<R> select(Function<SelectModel, R> adapterFunction, BasicColumn ... selectList) {
        SelectDSL<R> selectModelBuilder = new SelectDSL<>(adapterFunction);
        return selectModelBuilder.queryExpressionBuilder(selectList);
    }

    public static FromGatherer<SelectModel> selectDistinct(BasicColumn ... selectList) {
        return selectDistinct(Function.identity(), selectList);
    }

    public static <R> FromGatherer<R> selectDistinct(Function<SelectModel, R> adapterFunction, BasicColumn ... selectList) {
        SelectDSL<R> selectModelBuilder = new SelectDSL<>(adapterFunction);
        return selectModelBuilder.distinctQueryExpressionBuilder(selectList);
    }

    public static <T> FromGatherer<MyBatis3SelectModelAdapter<T>> selectWithMapper(
            Function<SelectStatementProvider, T> mapperMethod, BasicColumn ... selectList) {
        return select(selectModel -> MyBatis3SelectModelAdapter.of(selectModel, mapperMethod), selectList);
    }

    public static <T> FromGatherer<MyBatis3SelectModelAdapter<T>> selectDistinctWithMapper(
            Function<SelectStatementProvider, T> mapperMethod, BasicColumn ... selectList) {
        return selectDistinct(selectModel -> MyBatis3SelectModelAdapter.of(selectModel,mapperMethod), selectList);
    }

    void addQueryExpression(QueryExpressionModel queryExpression) {
        queryExpressions.add(queryExpression);
    }

    void setOrderByModel(OrderByModel orderByModel) {
        this.orderByModel = orderByModel;
    }

    public R build() {
        SelectModel selectModel = SelectModel.withQueryExpressions(queryExpressions)
                .withOrderByModel(orderByModel)
                .build();
        return adapterFunction.apply(selectModel);
    }

}
